//////////////////////////////////////////////////////////////////////
// SLexer.cpp: implementation of the SLexer class.
//
//////////////////////////////////////////////////////////////////////
#include "SLexer.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define PUSHONE( a)  mData.Append(a)
SLexer::SLexer(const char * p)
{
	mBuffer=p; 
	mSize = (int)strlen(p); 
	mRPtr=0;
	mType= -1;
}

SLexer::~SLexer()
{

}
short SLexer::ReadOne() 
{ 
	short val;
	if( mRPtr<mSize) val=mBuffer[mRPtr++];
	 else val=0; 
	return val;
}
static int isSeparator(short ch){
        if( isspace(ch)) return 1;
		return ch=='['|| ch==']'||ch=='{'||ch=='}'||ch==','||ch==':';
    }
void SLexer::Push(int k)
{
	mType = k;
}
int SLexer::Scan()
{
    short val;
	if( mType>=0 ){
		int i=mType;
		mType = -1;
		return i;
	}
	mData.Trunc();
    while ( 1 )  {
		val = ReadOne();
		if( val == 0 ) break;
		mFirst = mRPtr;
        char ch = char(val);
        switch (ch){
		case '\t':
        case ' ' : continue;
        case ',' : 
		case ':' : 
        case ']' : 
        case '{' : 
        case '}' : 
        case '[' :// if (block_brack) return lbrack(CL_NONE);
                   //else
			mData.Append(ch);
			return ch;
		case '\n':
		case '\r':
			continue;
        case '"' : return ReadQuote(ch, LX_STRING);
        case '\'': return ReadQuote(ch, LX_STRING);
        default:
            if (iscntrl(ch)) continue;
			if( isspace(ch) ) continue;
                return ReadIdentify(ch);
 //           sprintf(msg,"identify can not begin witch %c",ch);
   //         return -1;            
        }
	}
    return LX_NULL;
}
int SLexer::ReadQuote (char c, int s)
{
	int count;
	int code =0;
	short val;
	mData.Remove();
	PUSHONE(c);
    while ( (val = ReadOne()) != c) {
		if ( val == 0 ) {
			sprintf(msg,"unexpect end  while look for %c",c);
			return -1; 
		}
		if (val == '\n'){
			sprintf(msg,"unexpect new line while look for %c",c);
			return -1;
		}
        if (val == '\\') {
			if( (val = ReadOne())==0 ){
				sprintf(msg,"unexpect end  while look for %c",c);
				return -1;
			}
            if (val == '\n')  continue;			            
			switch( val ){
			case '\\': case '\'': case '"': case '/': 	break;
		    case 'n': val ='\n';break;
		    case 't': val ='\t';break;
			case 'r': val ='\r';break;
		    case 'f': val ='\f';break;
		    case 'b': val ='\b';break;
			case 'a': val ='\a';break;
			case 'v': val ='\v';break;
			case 'c': 
				{
					if( (val = ReadOne())==0 ){
						sprintf(msg,"unexpect end  while look for %c",c);
						return -1;
					}
					switch(val){
					case '@': val=0;break;
					case '[': val=0x1b;break;
					case '/': val=0x1c;break;
					case ']': val=0x1d;break;
					case '^': val=0x1e;break;
					case '_': val=0x1f;break;
				    default:
					 val=val&0x1F;
					}
					if( val<0 ) val ='c';
				}
				break;
			case 'x':// hex number
				{
					code =0;
					count = 0;
					ReadOne();
					if (!(val >= 'a' && val <= 'f') && !(val >= 'A' && val <= 'F')
					     && !(val >= '0' && val <= '9'))
					    break;
				    if (val >= 'a' && val <= 'f')	code += val - 'a' + 10;
				    if (val >= 'A' && val <= 'F')	code += val - 'A' + 10;
				    if (val >= '0' && val <= '9')	code += val - '0';

					ReadOne();
					if (!(val >= 'a' && val <= 'f')&& !(val >= 'A' && val <= 'F')
					    && !(val >= '0' && val <= '9'))
					   break;
				   code *=16;
				   if (val >= 'a' && val <= 'f')	code += val - 'a' + 10;
				   if (val >= 'A' && val <= 'F')	code += val - 'A' + 10;
				   if (val >= '0' && val <= '9')	code += val - '0';
				   PUSHONE(code);
				   continue;
				}
		    case '0':  case '1':  case '2':  case '3':  case '4':
			case '5':  case '6':  case '7':
				{
					code = 0;
					count = 0;
					while ((val <= '7') && (val >= '0') && (count++ < 3))
					{
						code = (code * 8) + (val - '0');
						ReadOne();
					}
					if( count>0) PUSHONE(code);
					continue;
				}
			default:
				PUSHONE('\\');   // this handles \' and \" too.
			}
		}
        PUSHONE((char)val);
    }
//	PutBack();
	PUSHONE(c);
    return s;
}

int SLexer::ReadIdentify(char ch)
{
    //register BOOL maybe_kw = TRUE;
    //register short bs = 0;
	short val=ch;
    while ( !isSeparator(val) ) {
		mData.Append((char)val);       // don't worry about overflow
        val = ReadOne();
    }
	PutBack();
    return LX_ID;
}
